////////////////////////////////////////////////////////////////////////////////

#include "server_session.h"

////////////////////////////////////////////////////////////////////////////////

#include "server.h"
#include <boost/bind.hpp>
#include <iostream>

////////////////////////////////////////////////////////////////////////////////


ServerSession::ServerSession( boost::asio::io_service& _io_service,
                              Server* _coordinator )
: m_IsOK(true),
  m_io_service(_io_service),
  m_Socket(m_io_service),
  m_Server(_coordinator)
{
}


////////////////////////////////////////////////////////////////////////////////


ServerSession::~ServerSession()
{
}


////////////////////////////////////////////////////////////////////////////////


tcp::socket& ServerSession::GetSocket()
{
    return m_Socket;
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::Send( const ServerPacket& _packet )
{
    bool sendNow = m_SendQueue.empty();
    m_SendQueue.push(_packet);

    // If there are some packets in queue, just push the packet
    // It will be sent automatically
    if (sendNow)
        StartSend();
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::StartSend()
{
    // Send packet
    m_SendBuffer = m_SendQueue.front().ToStr();
    m_Socket.async_write_some( boost::asio::buffer(m_SendBuffer),
                               boost::bind( &ServerSession::HandleSend, this,
                                             boost::asio::placeholders::error,
                                             boost::asio::placeholders::bytes_transferred ) );
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::HandleSend( const boost::system::error_code& _error,
                                size_t _bytesReceived )
{
    if (!_error)
    {
        // Continue
        m_SendQueue.pop();
        if ( !m_SendQueue.empty() )
            StartSend();
    }
    else
    {
        // Stop on error
        m_Socket.close();
        m_IsOK = false;
    }
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::Receive()
{
    m_Socket.async_read_some( boost::asio::buffer(m_RecvBuffer),
                              boost::bind( &ServerSession::HandleReceive,
                                           this,
                                           boost::asio::placeholders::error,
                                           boost::asio::placeholders::bytes_transferred) );
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::HandleReceive( const boost::system::error_code& _error,
                                   size_t _bytesReceived )
{
    if (!_error)
    {
        size_t bytesLeft = _bytesReceived;
        size_t offset = 0;
        while (bytesLeft > 0)
        {
            ClientPacket packet;
            packet.FromStr(m_RecvBuffer.data() + offset);

            offset += packet.Size();
            bytesLeft -= packet.Size();

            m_Server->Receive(packet);
        }
        Receive();
    }
    else
    {
        m_Socket.close();
        m_IsOK = false;
    }
}


////////////////////////////////////////////////////////////////////////////////


bool ServerSession::IsOK() const
{
    return m_IsOK;
}


////////////////////////////////////////////////////////////////////////////////
